package tank

import (
	"errors"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"net/http"
	"net/mail"
	"regexp"
	"server/config"
	db "server/data"
	"strings"
)

type registerReq struct {
	Email    string `form:"email" binding:"required"`
	Password string `form:"password" binding:"required,lte=24"`
}

var errEmailNotSupported = errors.New("不支持该邮箱")
var errPasswordTooShort = errors.New("密码需6位及以上")
var errPasswordInvalid = errors.New("密码无效")
var errEmailListIsEmpty = errors.New("邮箱列表为空")

var sohuEmailSuffix = "sohu-inc.com"
var changyouEmailSuffix = "cyou-inc.com"

func (r *registerReq) validEmail() error {
	if _, err := mail.ParseAddress(r.Email); err != nil {
		return err
	}
	if strings.HasSuffix(r.Email, sohuEmailSuffix) || strings.HasSuffix(r.Email, changyouEmailSuffix) {
		return errEmailNotSupported
	}
	return nil
}

func (r *registerReq) validPassword() error {
	if len(r.Password) < 6 {
		return errPasswordTooShort
	}
	re := regexp.MustCompile(`^[\x00-\x7F]+$`)
	if !re.MatchString(r.Password) {
		return errPasswordInvalid
	}
	return nil
}

func Register(c *gin.Context) {
	var req registerReq
	if err := c.ShouldBind(&req); err != nil {
		c.JSON(http.StatusOK, gin.H{"status": http.StatusBadRequest, "desc": err.Error()})
		return
	}

	if err := req.validEmail(); err != nil {
		if errors.Is(err, errEmailNotSupported) {
			c.JSON(http.StatusOK, gin.H{"status": config.BusinessSuccessCode, "desc": err.Error(), "data": gin.H{"regStatus": 4}})
			return
		}
		c.JSON(http.StatusOK, gin.H{"status": config.BusinessSuccessCode, "desc": "邮箱格式不正确", "data": gin.H{"regStatus": 2}})
		return
	}
	if err := req.validPassword(); err != nil {
		c.JSON(http.StatusOK, gin.H{"status": config.BusinessSuccessCode, "desc": err.Error(), "data": gin.H{"regStatus": 3}})
		return
	}

	user := db.User{Email: req.Email, Password: req.Password}
	result := db.DB.Debug().FirstOrCreate(&user, db.User{Email: req.Email})
	if result.RowsAffected == 0 {
		c.JSON(http.StatusOK, gin.H{"status": config.BusinessSuccessCode, "desc": "该邮箱已注册", "data": gin.H{"regStatus": 1}})
		return
	}
	c.JSON(http.StatusOK, gin.H{"status": config.BusinessSuccessCode, "desc": "success", "data": gin.H{"regStatus": 0}})
}

type loginReq struct {
	Email    string `form:"email" binding:"required"`
	Password string `form:"password" binding:"required"`
}

func Login(c *gin.Context) {
	var req loginReq
	if err := c.ShouldBind(&req); err != nil {
		c.JSON(http.StatusOK, gin.H{"status": http.StatusBadRequest, "desc": err.Error()})
		return
	}

	var user db.User
	err := db.DB.Debug().Where(db.User{Email: req.Email}).First(&user).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.JSON(http.StatusOK, gin.H{"Status": config.BusinessSuccessCode, "desc": "邮箱地址未注册", "data": gin.H{"loginStatus": 1}})
			return
		}
		c.JSON(http.StatusOK, gin.H{"status": http.StatusBadRequest, "desc": err.Error()})
		return
	}

	if req.Password != user.Password {
		c.JSON(http.StatusOK, gin.H{"Status": config.BusinessSuccessCode, "desc": "密码不正确", "data": gin.H{"loginStatus": 2}})
		return
	}

	c.JSON(http.StatusOK, gin.H{"status": config.BusinessSuccessCode, "desc": "success", "data": gin.H{"loginStatus": 0}})
}

type listReq struct {
	JoinStatus  *int   `form:"joinStatus"`
	SearchEmail string `form:"searchEmail"`
}

type userListResp struct {
	EmailRegList []*userResp `json:"emailRegList"`
}

type userResp struct {
	Email      string `json:"email"`
	JoinStatus int    `json:"joinStatus"`
}

func List(c *gin.Context) {
	var req listReq
	if err := c.ShouldBind(&req); err != nil {
		c.JSON(http.StatusOK, gin.H{"status": http.StatusBadRequest, "desc": err.Error()})
		return
	}

	var users []*db.User
	query := db.DB.Debug().Model(&db.User{})
	if req.JoinStatus != nil {
		query = query.Where("join_status = ?", req.JoinStatus)
	}
	if req.SearchEmail != "" {
		query = query.Where("email like ?", "%"+req.SearchEmail+"%")
	}
	query.Find(&users)

	resp := userListResp{}
	regList := []*userResp{}
	for _, user := range users {
		regList = append(regList, &userResp{JoinStatus: user.JoinStatus, Email: user.Email})
	}
	resp.EmailRegList = regList

	c.JSON(http.StatusOK, gin.H{"status": config.BusinessSuccessCode, "desc": "success", "data": resp})
}

type updateReq struct {
	JoinStatus *int     `form:"joinStatus" binding:"required"`
	Emails     []string `form:"emails" binding:"required"`
}

func (u *updateReq) valid() bool {
	if len(u.Emails) == 0 {
		return false
	}
	return true
}

func UpdateJoinStatus(c *gin.Context) {
	var req updateReq
	if err := c.ShouldBind(&req); err != nil {
		c.JSON(http.StatusOK, gin.H{"status": http.StatusBadRequest, "desc": err.Error()})
		return
	}
	if !req.valid() {
		c.JSON(http.StatusOK, gin.H{"status": http.StatusBadRequest, "desc": errEmailListIsEmpty.Error()})
		return
	}

	if result := db.DB.Debug().Model(&db.User{}).Where("email IN ?", req.Emails).Update("join_status", req.JoinStatus); result.Error != nil {
		c.JSON(http.StatusOK, gin.H{"status": http.StatusBadRequest, "desc": result.Error.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"status": config.BusinessSuccessCode, "desc": "success"})
}
